﻿Imports WiremetModel.Entities.SupplyOrders
Imports GMap.NET
Imports GMap.NET.WindowsForms
Imports WiremetModel.Exceptions
Imports CrystalDecisions.CrystalReports.Engine
Imports WiremetModel.Entities

Public Class WireOrderView

    Private _unitOfWork As UnitOfWork
    Private _wireOrderDictionary As IDictionary(Of Integer, WireOrder)
    Private _supplierLocationOverlay As GMapOverlay
    Private _detailsPanelWidth As Integer

    Private Structure Filter
        Public orderNumber As String
        Public supplierId As Integer
        Public submitDate As Date?
        Public orderLineMaterialGradeId As Integer
        Public orderLineDiameter As String
    End Structure


    Public Sub New()
        InitializeComponent()
        _unitOfWork = New UnitOfWork()
        RefreshView()
    End Sub

    Private Sub WireOrderView_FormClosed(ByVal sender As Object, ByVal e As FormClosedEventArgs) Handles Me.FormClosed
        _unitOfWork.Dispose()
    End Sub

    Private Sub RefreshView()
        RefreshViewData()
        RefreshWireOrderTable(_wireOrderDictionary.Values)
    End Sub

    Private Sub RefreshViewData()

        Dim wireOrderRepository As New Repository(Of WireOrder)(_unitOfWork)
        Dim supplierRepository As New Repository(Of Supplier)(_unitOfWork)
        Dim materialGradeRepository As New Repository(Of OEM.Gatunek)(_unitOfWork)

        _wireOrderDictionary = wireOrderRepository.GetAll().ToDictionary(Function(x) x.Id, Function(x) x)
        Dim supplierList As IEnumerable(Of Supplier) = supplierRepository.GetAll()
        Dim materialGradeList As IEnumerable(Of OEM.Gatunek) = materialGradeRepository.GetAll()

        InitializeFilterComboBox(cmb_Filter_Supplier, supplierList)
        InitializeFilterComboBox(cmb_Filter_OrderLineMaterialGrade, materialGradeList)

    End Sub

    Private Sub InitializeFilterComboBox(ByRef inputComboBox As ComboBox, ByVal data As IEnumerable(Of Object))
        inputComboBox.DataSource = New BindingSource(data, Nothing)
        inputComboBox.AutoCompleteCustomSource.Clear()
        inputComboBox.AutoCompleteCustomSource.AddRange(data.Select(Function(x) x.ToString()).ToArray())
        inputComboBox.SelectedIndex = -1
    End Sub

    Private Sub RefreshWireOrderTable(ByVal wireOrderList As IEnumerable(Of WireOrder))

        dgv_WireOrder.Rows.Clear()
        For Each wireOrder As WireOrder In wireOrderList.OrderByDescending(Function(x) x.OrderNumber)
            dgv_WireOrder.Rows.Add(
                wireOrder.Id,
                wireOrder.OrderNumber,
                wireOrder.Supplier.CompanyName,
                wireOrder.SubmitDate.ToShortDateString(),
                If(wireOrder.ExpectedDeliveryDate.HasValue, wireOrder.ExpectedDeliveryDate.Value.ToShortDateString(), String.Empty),
                wireOrder.OrderLines.Sum(Function(x) Math.Round(x.Quantity * x.UnitPrice, 2)).ToString() & " " & wireOrder.Currency.Nazwa
            )
        Next
    End Sub

    Private Function GetSelectedWireOrder() As WireOrder
        Return _wireOrderDictionary(CInt(dgv_WireOrder.SelectedRows(0).Cells("WireOrderId").Value))

    End Function

    Private Sub RefreshDetailsPanel()
        Dim wireOrder As WireOrder = GetSelectedWireOrder()

        tb_Employee.Text = wireOrder.Employee.ToString()
        tb_Note.Text = wireOrder.Note
        Dim supplierAddres As SupplierAddress = wireOrder.Supplier.SupplierAddresses.FirstOrDefault(Function(x) x.Address.Id = wireOrder.SubmitAddress.Id)
        tb_SubmitAddress.Text = If(IsNothing(supplierAddres), "Usunięty", supplierAddres.Description) & vbNewLine &
            wireOrder.SubmitAddress.ToString()

        tb_TelephoneNumber.Text = wireOrder.Supplier.TelephoneNumber
        tb_FaxNumber.Text = wireOrder.Supplier.FaxNumber
        tb_EmailAddress.Text = wireOrder.Supplier.EmailAddress


        dgv_WireOrderLine.Rows.Clear()
        For Each wireOrderLine As WireOrderLine In wireOrder.OrderLines

            dgv_WireOrderLine.Rows.Add(
                wireOrderLine.Id,
                wireOrderLine.Diameter,
                wireOrderLine.MaterialGrade.NazwaAng,
                wireOrderLine.Quantity & " " & wireOrderLine.MeasureUnit.Jednostka,
                wireOrderLine.UnitPrice,
                Math.Round(wireOrderLine.Quantity * wireOrderLine.UnitPrice, 2)
            )
        Next
    End Sub

    Private Sub dgv_WireOrder_SelectionChanged(ByVal sender As Object, ByVal e As EventArgs) Handles dgv_WireOrder.SelectionChanged
        If Not sc_WireOrderData.Panel2Collapsed AndAlso Not dgv_WireOrder.SelectedRows.Count = 0 Then
            RefreshDetailsPanel()
        End If
    End Sub



#Region "Filter"

    Private Function CreateFilter() As Filter
        Return New Filter With
        {
            .orderNumber = tb_Filter_OrderNumber.Text.Trim(),
            .submitDate = If(dtp_Filter_SumbitDate.Checked, dtp_Filter_SumbitDate.Value, CType(Nothing, Date?)),
            .supplierId = If(IsNothing(cmb_Filter_Supplier.SelectedItem), 0, CType(cmb_Filter_Supplier.SelectedItem, Supplier).Id),
            .orderLineMaterialGradeId = If(IsNothing(cmb_Filter_OrderLineMaterialGrade.SelectedItem), 0, CType(cmb_Filter_OrderLineMaterialGrade.SelectedItem, OEM.Gatunek).Id),
            .orderLineDiameter = tb_Filter_OrderLineDiameter.Text.Trim()
        }
    End Function


    Private Function IsWireOrderSatisfiedByFilter(ByVal wireOrder As WireOrder, ByVal filter As Filter) As Boolean
        Return wireOrder.OrderNumber.StartsWith(filter.orderNumber, StringComparison.CurrentCultureIgnoreCase) AndAlso
            (filter.supplierId = 0 OrElse wireOrder.Supplier.Id = filter.supplierId) AndAlso
            (Not filter.submitDate.HasValue OrElse wireOrder.SubmitDate.ToShortDateString() = filter.submitDate.Value.ToShortDateString()) AndAlso
            (filter.orderLineMaterialGradeId = 0 OrElse wireOrder.OrderLines.Any(Function(x) x.MaterialGrade.Id = filter.orderLineMaterialGradeId)) AndAlso
            (wireOrder.OrderLines.Any(Function(x) x.Diameter.ToString().StartsWith(filter.orderLineDiameter)))
    End Function


    Private Sub RunFilter(ByVal filter As Filter)
        Dim filteredWireOrderList As New List(Of WireOrder)

        For Each wireOrder As WireOrder In _wireOrderDictionary.Values
            If IsWireOrderSatisfiedByFilter(wireOrder, filter) Then
                filteredWireOrderList.Add(wireOrder)
            End If
        Next

        RefreshWireOrderTable(filteredWireOrderList)
        ComboBoxCleanupWhenNoValueSelected(cmb_Filter_Supplier)
    End Sub


    Private Sub ComboBoxCleanupWhenNoValueSelected(ByRef comboBox As ComboBox)
        If comboBox.SelectedValue Is Nothing Then
            comboBox.ResetText()
        End If
    End Sub


    Private Sub ClearFilter()

        tb_Filter_OrderNumber.Text = String.Empty
        dtp_Filter_SumbitDate.Value = Date.Now
        dtp_Filter_SumbitDate.Checked = False
        cmb_Filter_Supplier.SelectedIndex = -1
        cmb_Filter_Supplier.ResetText()
        tb_Filter_OrderLineDiameter.Text = String.Empty
        cmb_Filter_OrderLineMaterialGrade.SelectedIndex = -1
        cmb_Filter_OrderLineMaterialGrade.ResetText()

    End Sub

    Private Sub btn_RunFilter_Click(sender As System.Object, e As System.EventArgs) Handles btn_RunFilter.Click
        RunFilter(CreateFilter())
    End Sub

    Private Sub btn_ClearFilter_Click(sender As System.Object, e As System.EventArgs) Handles btn_ClearFilter.Click
        ClearFilter()
        RunFilter(CreateFilter())
    End Sub

    Private Sub filterInput_KeyDown(sender As Object, e As KeyEventArgs) Handles tb_Filter_OrderNumber.KeyDown, cmb_Filter_Supplier.KeyDown, dtp_Filter_SumbitDate.KeyDown, cmb_Filter_OrderLineMaterialGrade.KeyDown, tb_Filter_OrderLineDiameter.KeyDown
        If e.KeyCode = Keys.Enter Then
            RunFilter(CreateFilter())
        End If
    End Sub
#End Region

    Private Sub EnsureWireOrderIsSelected()
        If dgv_WireOrder.SelectedRows.Count = 0 Then
            Throw New Exception("Proszę, wybierz zamówienie, aby kontynuować.")
        End If
    End Sub
    Private Sub PresentWireOrderReport(ByVal wireOrder As WireOrder)
        Dim wireOrderReport As ReportDocument = New WireOrderReportService().GenerateReport(wireOrder)
        Dim reportPreviewForm As New frmPrintViewer(wireOrderReport, False)
        reportPreviewForm.WindowState = FormWindowState.Maximized
        reportPreviewForm.Show()
    End Sub

    Private Sub ts_btn_AddWireOrder_Click(sender As System.Object, e As System.EventArgs) Handles ts_btn_AddWireOrder.Click
        Try
            Dim wireOrderInputDialog As New WireOrderInputDialog(_unitOfWork)
            If wireOrderInputDialog.ShowDialog = Windows.Forms.DialogResult.OK Then
                Cursor = Cursors.WaitCursor

                Dim wireOrder As WireOrder = wireOrderInputDialog.WireOrder
                Dim wireOrderRepository As New Repository(Of WireOrder)(_unitOfWork)

                _unitOfWork.BeginTransaction()
                wireOrderRepository.Add(wireOrder)
                _unitOfWork.CommitTransaction()

                PresentWireOrderReport(wireOrder)

                _wireOrderDictionary.Add(wireOrder.Id, wireOrder)
                RefreshWireOrderTable(_wireOrderDictionary.Values)
                ClearFilter()
                RunFilter(CreateFilter())

            End If
        Catch ex As Exception
            If _unitOfWork.IsTransactionActive Then
                _unitOfWork.RollbackTransaction()
                _unitOfWork.DisposeTransaction()
            End If
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            Cursor = Cursors.Default
        End Try
    End Sub

    Private Sub ts_btn_EditWireOrder_Click(sender As System.Object, e As System.EventArgs) Handles ts_btn_EditWireOrder.Click
        Try
            EnsureWireOrderIsSelected()
            Dim selectedWireOrder As WireOrder = GetSelectedWireOrder()
            Dim wireOrderInputDialog As New WireOrderInputDialog(_unitOfWork, selectedWireOrder)

            If wireOrderInputDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
                Cursor = Cursors.WaitCursor

                Dim wireOrder As WireOrder = wireOrderInputDialog.WireOrder
                Dim wireOrderRepository As New Repository(Of WireOrder)(_unitOfWork)

                _unitOfWork.BeginTransaction()
                wireOrderRepository.Update(wireOrder)
                _unitOfWork.CommitTransaction()

                PresentWireOrderReport(wireOrder)

                _wireOrderDictionary(wireOrder.Id) = wireOrder
                RefreshWireOrderTable(_wireOrderDictionary.Values)
                ClearFilter()
                RunFilter(CreateFilter())

            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            Cursor = Cursors.Default
        End Try
    End Sub

    Private Sub ts_btn_DeleteOrder_Click(sender As System.Object, e As System.EventArgs) Handles ts_btn_DeleteOrder.Click
        Try
            EnsureWireOrderIsSelected()
            Dim selectedWireOrder As WireOrder = GetSelectedWireOrder()
            Dim confirmationDialogResult As DialogResult = MessageBox.Show("Czy jesteś pewien?", "Uwaga", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)

            If confirmationDialogResult = DialogResult.Yes Then
                Cursor = Cursors.WaitCursor

                Dim wireOrderRepository As New Repository(Of WireOrder)(_unitOfWork)

                _unitOfWork.BeginTransaction()
                wireOrderRepository.Delete(selectedWireOrder)
                _unitOfWork.CommitTransaction()

                _wireOrderDictionary.Remove(selectedWireOrder.Id)
                RefreshWireOrderTable(_wireOrderDictionary.Values)

                MessageBox.Show("Zamówienie zostało usunięte.", "Potwierdzenie", MessageBoxButtons.OK, MessageBoxIcon.Information)
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            Cursor = Cursors.Default
        End Try
    End Sub

    Private Sub ts_btn_CopyOrder_Click(sender As System.Object, e As System.EventArgs) Handles ts_btn_CopyOrder.Click
        Try
            EnsureWireOrderIsSelected()
            Dim selectedWireOrder As WireOrder = GetSelectedWireOrder()
            Dim copiedOrder As New WireOrder With {
                .Currency = selectedWireOrder.Currency,
                .Employee = selectedWireOrder.Employee,
                .Note = selectedWireOrder.Note,
                .OrderLines = selectedWireOrder.OrderLines.Select(Function(x) New WireOrderLine With {
                                                                      .Diameter = x.Diameter,
                                                                      .DiameterToleranceMinus = x.DiameterToleranceMinus,
                                                                      .DiameterTolerancePlus = x.DiameterTolerancePlus,
                                                                      .EnduranceMax = x.EnduranceMax,
                                                                      .EnduranceMin = x.EnduranceMin,
                                                                      .MaterialGrade = x.MaterialGrade,
                                                                      .MeasureUnit = x.MeasureUnit,
                                                                      .Packaging = x.Packaging,
                                                                      .Quantity = x.Quantity,
                                                                      .UnitPrice = x.UnitPrice
                                                                      }).ToList(),
                .SubmitAddress = selectedWireOrder.SubmitAddress,
                .SubmitDate = Date.Now.Date,
                .Supplier = selectedWireOrder.Supplier
            }
            '
            '.ExpectedDeliveryDate = selectedWireOrder.ExpectedDeliveryDate,
            For Each orderLine As WireOrderLine In copiedOrder.OrderLines
                orderLine.WireOrder = copiedOrder
            Next

            Dim wireOrderInputDialog As New WireOrderInputDialog(_unitOfWork, copiedOrder)
            If wireOrderInputDialog.ShowDialog = Windows.Forms.DialogResult.OK Then
                Cursor = Cursors.WaitCursor

                Dim wireOrder As WireOrder = wireOrderInputDialog.WireOrder
                Dim wireOrderRepository As New Repository(Of WireOrder)(_unitOfWork)

                _unitOfWork.BeginTransaction()
                wireOrderRepository.Add(wireOrder)
                _unitOfWork.CommitTransaction()

                PresentWireOrderReport(wireOrder)

                _wireOrderDictionary.Add(wireOrder.Id, wireOrder)
                RefreshWireOrderTable(_wireOrderDictionary.Values)
                ClearFilter()
                RunFilter(CreateFilter())

            End If
        Catch ex As Exception
            If _unitOfWork.IsTransactionActive Then
                _unitOfWork.RollbackTransaction()
                _unitOfWork.DisposeTransaction()
            End If
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            Cursor = Cursors.Default
        End Try
    End Sub

    Private Sub ts_btn_RefreshView_Click(sender As System.Object, e As System.EventArgs) Handles ts_btn_RefreshView.Click
        Try
            Cursor = Cursors.WaitCursor
            _unitOfWork.Dispose()
            _unitOfWork = New UnitOfWork()
            RefreshViewData()
            ClearFilter()
            RunFilter(CreateFilter())
            Cursor = Cursors.Default
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            Cursor = Cursors.Default
        End Try
    End Sub

    Private Sub ts_btn_PrintWireOrder_Click(sender As System.Object, e As System.EventArgs) Handles ts_btn_PrintWireOrder.Click
        Try
            EnsureWireOrderIsSelected()
            Cursor = Cursors.WaitCursor
            Dim selectedWireOrder As WireOrder = GetSelectedWireOrder()
            PresentWireOrderReport(selectedWireOrder)
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            Cursor = Cursors.Default
        End Try
    End Sub

    Private Sub ChangeDetailsPanelVisibility()
        sc_WireOrderData.SplitterWidth = 15
        If sc_WireOrderData.Panel2Collapsed Then
            sc_WireOrderData.Panel2Collapsed = False
            Me.Width += _detailsPanelWidth + sc_WireOrderData.SplitterWidth
        Else
            _detailsPanelWidth = sc_WireOrderData.Panel2.Width
            Me.Width -= _detailsPanelWidth + sc_WireOrderData.SplitterWidth
            sc_WireOrderData.Panel2Collapsed = True
        End If
        Refresh()
    End Sub

    Private Sub ts_btn_Details_Click(sender As System.Object, e As System.EventArgs) Handles ts_btn_Details.Click
        ChangeDetailsPanelVisibility()
        RefreshDetailsPanel()
    End Sub

    
End Class